//
//  AlgorithmFunctionsTest.cpp
//  GRE
//
//  Created by Kutlak Roman on 08/03/2012.
//  Copyright (c) 2012 University of Aberdeen. All rights reserved.
//

#include <gtest/gtest.h>

#include "AlgorithmFunctions.h"
#include "KnowledgeBase.h"
#include "Ontology.h"
#include "RefExp.h"

using namespace kutlak::roman::gre;


TEST(AlgorithmFunctions, RulesOut) {
    pKnowledgeBase kb(new KnowledgeBase("/Users/roman/Projects/NLP/GRE/resources/example.nt"));
    ContainerT distractors = kb->Entities();
    
    int res;
    
    res = RulesOut(distractors, Property("contains", "metal"));
    EXPECT_EQ(0, res);
    
    res = RulesOut(distractors, Property("origin", "Italy"));
    EXPECT_EQ(2, res);
    
    res = RulesOut(distractors, Property("origin", "Sweden"));
    EXPECT_EQ(3, res);
    
    res = RulesOut(distractors, Property("origin", "Czech"));
    EXPECT_EQ(5, res);
    
    // functions are non-destructive
    EXPECT_EQ(5, distractors.size());
}

TEST(AlgorithmFunctions, Filter) {
    pKnowledgeBase kb(new KnowledgeBase("/Users/roman/Projects/NLP/GRE/resources/example.nt"));
    ContainerT distractors = kb->Entities();
    EntityPtrT ref = kb->EntityPtrByName("a");
    
    if (!ref) {
        cerr << "Error: Referent not found.\n";
        return;
    }
    
    int res;

    // entities
    res = Filter(distractors, ref);
    EXPECT_EQ(1, res);
    EXPECT_EQ(4, distractors.size());
    
    // properties
    distractors = kb->Entities();
    res = Filter(distractors, Property("contains", "metal"));
    EXPECT_EQ(0, res);
    EXPECT_EQ(5, distractors.size());
    
    res = Filter(distractors, Property("origin", "Italy"));
    EXPECT_EQ(2, res);
    EXPECT_EQ(3, distractors.size());
    
    res = Filter(distractors, Property("origin", "Sweden"));
    EXPECT_EQ(3, res);
    EXPECT_EQ(0, distractors.size());
    
    distractors = kb->Entities();
    res = Filter(distractors, Property("origin", "Czech"));
    EXPECT_EQ(5, res);
    EXPECT_EQ(0, distractors.size());    
}

TEST(AlgorithmFunctions, HasDiscriminatoryPower) {
    pKnowledgeBase kb(new KnowledgeBase("/Users/roman/Projects/NLP/GRE/resources/example.nt"));
    ContainerT distractors = kb->Entities();
    EntityPtrT ref = kb->EntityPtrByName("a");
    
    if (!ref) {
        cerr << "Error: Referent not found.\n";
        return;
    }
    
    bool res;
    
    res = HasDiscriminatoryPower(distractors, Property("contains", "metal"));
    EXPECT_EQ(false, res);
    
    res = HasDiscriminatoryPower(distractors, Property("origin", "Italy"));
    EXPECT_EQ(true, res);
    
    res = HasDiscriminatoryPower(distractors, Property("origin", "Finland"));
    EXPECT_EQ(true, res);
    
    res = HasDiscriminatoryPower(distractors, Property("origin", "Czech"));
    EXPECT_EQ(true, res);
    
    // functions are non-destructive
    EXPECT_EQ(5, distractors.size());
    
    
    // remove the referent
    res = Filter(distractors, ref);
    EXPECT_EQ(1, res);
    EXPECT_EQ(4, distractors.size());
    
    
    res = HasDiscriminatoryPower(distractors, Property("contains", "metal"));
    EXPECT_EQ(false, res);
    
    res = HasDiscriminatoryPower(distractors, Property("origin", "Italy"));
    EXPECT_EQ(true, res);
    
    res = HasDiscriminatoryPower(distractors, Property("origin", "Finland"));
    EXPECT_EQ(true, res);
    
    res = HasDiscriminatoryPower(distractors, Property("origin", "Czech"));
    EXPECT_EQ(true, res);
    
    // functions are non-destructive
    EXPECT_EQ(4, distractors.size());
}

TEST(AlgorithmFunctions, DiscriminatoryPower) {
    pKnowledgeBase kb(new KnowledgeBase("/Users/roman/Projects/NLP/GRE/resources/example.nt"));
    ContainerT distractors = kb->Entities();
    EntityPtrT ref = kb->EntityPtrByName("a");
    
        if (!ref) {
        cerr << "Error: Referent not found.\n";
        return;
    }
    
    double res;
    
    res = DiscriminatoryPower(distractors, Property("contains", "metal"));
    EXPECT_EQ(0, res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Italy"), 1);
    EXPECT_EQ( ((5.0-3.0) / (5.0 - 1.0)), res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Finland"), 1);
    EXPECT_EQ( ((5.0-1.0) / (5.0 - 1.0)), res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Sweden"), 1);
    EXPECT_EQ( ((5.0-2.0) / (5.0 - 1.0)), res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Czech"), 1);
    EXPECT_EQ( 1.0 /*((5.0-0.0) / (5.0 - 1.0)) rounded to 1.0 */, res);
    
    // functions are non-destructive
    EXPECT_EQ(5, distractors.size());
    
    
    // remove the referent
    res = Filter(distractors, ref);
    EXPECT_EQ(1, res);
    EXPECT_EQ(4, distractors.size());
    
    
    res = DiscriminatoryPower(distractors, Property("contains", "metal"));
    EXPECT_EQ(0, res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Italy"));
    EXPECT_EQ( ((4.0-3.0) / 4.0), res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Finland"));
    EXPECT_EQ( ((4.0-0.0) / 4.0), res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Sweden"));
    EXPECT_EQ( ((4.0-1.0) / 4.0), res);
    
    res = DiscriminatoryPower(distractors, Property("origin", "Czech"));
    EXPECT_EQ( ((4.0-0.0) / 4.0), res);
    
    // functions are non-destructive
    EXPECT_EQ(4, distractors.size());
}

TEST(AlgorithmFunctions, ExtensionSize) {
    pKnowledgeBase kb(new KnowledgeBase("/Users/roman/Projects/NLP/GRE/resources/example.nt"));
    ContainerT distractors = kb->Entities();
    
    int res;
    
    res = ExtensionSize(distractors, Property("contains", "metal"));
    EXPECT_EQ(5, res);
    
    res = ExtensionSize(distractors, Property("origin", "Italy"));
    EXPECT_EQ(3, res);
    
    res = ExtensionSize(distractors, Property("origin", "Sweden"));
    EXPECT_EQ(2, res);
    
    res = ExtensionSize(distractors, Property("origin", "Czech"));
    EXPECT_EQ(0, res);
    
    // functions are non-destructive
    EXPECT_EQ(5, distractors.size());
    
    RefExp re;
    res = ExtensionSize(distractors, re);
    EXPECT_EQ(5, res);
    
    re.Add(Property("contains", "metal"));
    res = ExtensionSize(distractors, re);
    EXPECT_EQ(5, res);
    
    re.Add(Property("origin", "Sweden"));
    res = ExtensionSize(distractors, re);
    EXPECT_EQ(2, res);
    
    re.Add(Property("origin", "Finland"));
    res = ExtensionSize(distractors, re);
    EXPECT_EQ(1, res);
    
    re.Clear();
    re.Add(Property("price", "150"));
    res = ExtensionSize(distractors, re);
    EXPECT_EQ(2, res);
    
    re.Add(Property("colour", "dark"));
    res = ExtensionSize(distractors, re);
    EXPECT_EQ(1, res);
    
    // functions are non-destructive
    EXPECT_EQ(5, distractors.size()); 
}

TEST(AlgorithmFunctions, Extension) {
    pKnowledgeBase kb(new KnowledgeBase("/Users/roman/Projects/NLP/GRE/resources/example.nt"));
    ContainerT distractors = kb->Entities();
    
    ContainerT res;
    
    res = Extension(distractors, Property("contains", "metal"));
    EXPECT_EQ(5, res.size());
    
    res = Extension(distractors, Property("origin", "Italy"));
    EXPECT_EQ(3, res.size());
    
    res = Extension(distractors, Property("origin", "Sweden"));
    EXPECT_EQ(2, res.size());
    
    res = Extension(distractors, Property("origin", "Czech"));
    EXPECT_EQ(0, res.size());
    
    // functions are non-destructive
    EXPECT_EQ(5, distractors.size());
    
    RefExp re;
    res = Extension(distractors, re);
    EXPECT_EQ(5, res.size());
    
    re.Add(Property("contains", "metal"));
    res = Extension(distractors, re);
    EXPECT_EQ(5, res.size());
    
    re.Add(Property("origin", "Sweden"));
    res = Extension(distractors, re);
    EXPECT_EQ(2, res.size());
    
    re.Add(Property("origin", "Finland"));
    res = Extension(distractors, re);
    EXPECT_EQ(1, res.size());
    
    re.Clear();
    re.Add(Property("price", "150"));
    res = Extension(distractors, re);
    EXPECT_EQ(2, res.size());
    
    re.Add(Property("colour", "dark"));
    res = Extension(distractors, re);
    EXPECT_EQ(1, res.size());
    
    // functions are non-destructive
    EXPECT_EQ(5, distractors.size()); 
}

TEST(AlgorithmFunctions, FindBestValue) {
//    Ontology::SetDefault(pOntology(new Ontology("/Users/roman/Projects/NLP/GRE/resources/ontology.nt")));
    pKnowledgeBase kb(new KnowledgeBase("/Users/roman/Projects/NLP/GRE/resources/example.nt"));
    ContainerT distractors = kb->Entities();
    EntityPtrT ref = kb->EntityPtrByName("a");
    
        if (!ref) {
        cerr << "Error: Referent not found.\n";
        return;
    }
    Filter(distractors, ref);
    
    Property p = FindBestValue(distractors, ref, Property(Ontology::kType, "desk"));
    EXPECT_EQ(Property(Ontology::kType, "funnyDesk"), p);
    
    p = FindBestValue(distractors, ref, Property("colour", "dark"));
    EXPECT_EQ(Property("colour", "brown"), p);
    
    p = FindBestValue(distractors, ref, Property("origin", "Sweden"));
    EXPECT_EQ(Property("origin", "Finland"), p);
    
    p = FindBestValue(distractors, ref, Property("price", "100"));
    EXPECT_EQ(Property("price", "100"), p);
}








